#include "Texture.h"
#include "stdafx.h"

Texture::Texture():typeMapping(rien)
{
	typeTexture = fonctionTexture;
	horizon = Vecteur(1.0f,0.0f,0.0f);
	vertical = Vecteur(0.0f,0.0f,1.0f);
	centre = Point(0.0f,0.0f, 0.0f,1.0f);
	coffTexture = 1.0f;
}

Texture::Texture(TypeTextureMapping type1)
{
	typeMapping = type1;
	typeTexture = fonctionTexture;
	horizon = Vecteur(1.0f,0.0f,0.0f);
	vertical = Vecteur(0.0f,0.0f,1.0f);
	centre = Point(0.0f,0.0f, 0.0f,1.0f);
	coffTexture = 1.0f;
}

Texture::Texture(TypeTextureMapping type1, TypeTexture type2, PPMImage image1)
{
	typeMapping = type1;
	typeTexture = type2;
	image = image1;
	horizon = Vecteur(1.0f,0.0f,0.0f);
	vertical = Vecteur(0.0f,0.0f,1.0f);
	centre = Point(0.0f,0.0f, 0.0f,1.0f);
	coffTexture = 1.0f;
}

Texture::~Texture(){}

bool Texture::getTexture()
{
	if(typeMapping != rien)
		return true;
	else
		return false;
}

void Texture::setTextureMapping(TypeTextureMapping type1)
{
	typeMapping = type1;
}

void Texture::setTextureImage(PPMImage image1)
{
	typeTexture = imageTexture;
	image = image1;
}

void Texture::setCentreTexture(Point centre1)
{
	centre = centre1;
}

void Texture::setVertical(Vecteur vertical1)
{
	vertical = vertical1;
	vertical.normalize();
}

void Texture::setHorizon(Vecteur horizon1)
{
	horizon = horizon1;
	horizon.normalize();
}

void Texture::setCoffTexture(float coffTexture1)
{
	coffTexture = coffTexture1;
}

void Texture::setIsBillboard(bool flag)
{
	isBillboard = flag;
}


void Texture::getUVPlanar(Point p,float* u, float* v)
{
	Point p0;

	Vecteur v1 = vertical;

	Vecteur vup = horizon;
	vup.setZ(vup.getZ()+0.000001f);
	vup.normalize();
	 
	Vecteur w = v1.produitVectoriel(vup);
	w.normalize();

	vup = v1.produitVectoriel(w);
	vup.normalize();

	Matrice repere;

	repere.createGlobObs(w,vup,v1,centre);

	Vecteur vecteurP(p0,p);

	Vecteur vecteurP2 = repere * vecteurP;

	if(isBillboard)
	{
		Vecteur centreR = repere* (Vecteur(p0,centre));
		*u = (vecteurP2.getX()-centreR.getX())*coffTexture;
		*v = (vecteurP2.getY()-centreR.getY())*coffTexture;
	}
	else
	{
		*u = vecteurP2.getX()*coffTexture;
		*v = vecteurP2.getY()*coffTexture;
	}
}

/**
	http://www.cs.unc.edu/~rademach/xroads-RT/RTarticle.html
*/
void Texture::getUVSpherical(Point p,float* u, float* v)
{
	Vecteur vp = Vecteur(centre, p);
	vp.normalize();
	Vecteur vn(1.0f, 0.0f, 0.0f);
	Vecteur ve(0.0f, 0.0f, 1.0f);

	float phi = acos( -vp.produitScalaire(vn));
	*v = phi / PI;
	float theta = (acos((vp.produitScalaire(ve)) / sin( phi))) / ( 2 * PI);
	if ( vp.produitScalaire(vn.produitVectoriel(ve)) > 0 )
		*u = theta ;
	else
		*u = 1 - theta;

	*u = *u *coffTexture;
	*v = *v *coffTexture;
}

/*
	x = cos(2*PI*u)
	y = sin(2*PI*v)
	z = v
*/
void Texture::getUVCyclindrical(Point p,float* u, float* v)
{
	Point p0;

	Vecteur v1 = horizon;

	Vecteur vup = vertical;
	vup.setZ(vup.getZ()+0.000001f);
	vup.normalize();
	 
	Vecteur w = v1.produitVectoriel(vup);
	w.normalize();

	vup = v1.produitVectoriel(w);
	vup.normalize();

	Matrice repere;

	repere.createGlobObs(w,vup,v1,centre);

	Vecteur vecteurP(p0,p);

	Vecteur vecteurP2 = repere * vecteurP;
	Vecteur centreR = repere* (Vecteur(p0,centre));

	float x = vecteurP2.getX();
	float y = vecteurP2.getY();
	float z = vecteurP2.getZ();

	if(x==0.0f)
	{
		*u= y;
		*v= z;
	}
	else if(y ==0.0f)
	{
		*u = x;
		*v = y;
	}
	else
	{
		*u= (sqrt(x*x+y*y)-abs(y))/x;
		*v =z;
	}

	*u = *u *coffTexture;
	*v = *v *coffTexture;
}

Couleur Texture::getCouleurTexture(Point p)
{
	float u = 0.0f;
	float v = 0.0f;
	switch (typeMapping) {
		case planar:
			getUVPlanar(p,&u,&v);
			return getCouleur(u,v);
			break;
		case spherical:
			getUVSpherical(p,&u,&v);
			return getCouleur(u,v);
			break;
		case cyclindrical:
			getUVCyclindrical(p,&u,&v);
			return getCouleur(u,v);
			break;
		default:
			return Couleur(0,0,0);
	}
}

Couleur Texture::getCouleur(float u, float v)
{
	if(typeTexture==fonctionTexture)
	{
		while(u < 0)
		{
			u += 1;
		}

		while(v < 0)
		{
			v += 1;
		}
		int uInt = (int) (u*8);
		int vInt = (int) (v*8);

		if((uInt + vInt)%2==0)
			return Couleur(1.0f,1.0f,1.0f);
		else
			return Couleur(0.0f,0.0f,1.0f);
	}
	else
	{
		if(! isBillboard)
		{
			while(u < 0)
			{
				u += 1;
			}

			while(v < 0)
			{
				v += 1;
			}

			int uInt = (int) (u*image.getWidth());
			int vInt = (int) (v*image.getHeight());

			uInt = uInt % (image.getWidth());
			vInt = vInt % (image.getHeight());

			return image.getCouleur(uInt,vInt);
		}
		else
		{
			
			if(u>=0.5f || u <-0.5f || v >=0.5f || v <-0.5f)
				return Couleur(1.0f,1.0f,1.0f);
			else
			{
				int uInt = (int) ((u+0.5f)*image.getWidth());
				int vInt = (int) ((v+0.5f)*image.getHeight());
				return image.getCouleur(uInt,vInt);
			}
		}
	}
}
